package com.muyu.payment.service.impl;

import java.util.Date;
import java.util.List;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.muyu.common.core.enums.OrderEnum;
import com.muyu.common.core.web.page.PageQueryModel;
import com.muyu.payment.domain.PaymentIndent;
import com.muyu.payment.domain.model.*;
import com.muyu.payment.domain.req.PaymentCallbackReq;
import com.muyu.payment.domain.resp.PaymentCallbackResp;
import com.muyu.payment.service.PaymentOrderService;
import com.muyu.payment.service.PaymentDataSyncService;
import com.muyu.payment.domain.PaymentOrder;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.muyu.payment.mapper.PaymentIndentMapper;
import com.muyu.payment.service.PaymentIndentService;
import com.muyu.common.core.utils.IdGenerator;
import org.springframework.transaction.annotation.Transactional;

/**
 * 支付订单Service业务层处理
 *
 * @author muyu
 * @date 2025-09-18
 */
@Slf4j
@Service
public class PaymentIndentServiceImpl extends ServiceImpl<PaymentIndentMapper, PaymentIndent> implements PaymentIndentService {
    @Autowired
    private PaymentIndentMapper paymentIndentMapper;
    
    @Autowired
    private PaymentOrderService paymentOrderService;
    
    @Autowired
    private PaymentDataSyncService paymentDataSyncService;
    /**
     * 查询支付订单列表
     *
     * @param pageQueryModel 支付订单
     * @return 支付订单
     */
    @Override
    public PageQueryModel<PaymentIndentPageQueryModel> pageQuery(PaymentIndentQueryModel pageQueryModel) {
        Page<PaymentIndentPageQueryModel> page = new Page<>(pageQueryModel.getPageNum(), pageQueryModel.getPageSize());
        Page<PaymentIndentPageQueryModel> resultPage = paymentIndentMapper.pageQuery(page, pageQueryModel);
        return PageQueryModel.of(resultPage);
    }

    /**
     * 查询支付订单列表
     * @param pageQueryModel 支付订单
     * @return 支付订单
     */
    @Override
    public List<PaymentIndent> exportList(PaymentIndent pageQueryModel) {
        LambdaQueryWrapper<PaymentIndent> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ObjectUtil.isNotNull(pageQueryModel.getOrderNo()), PaymentIndent::getOrderNo, pageQueryModel.getOrderNo());
        queryWrapper.eq(ObjectUtil.isNotNull(pageQueryModel.getUserId()), PaymentIndent::getUserId, pageQueryModel.getUserId());
        queryWrapper.eq(ObjectUtil.isNotNull(pageQueryModel.getOrderStatus()), PaymentIndent::getOrderStatus, pageQueryModel.getOrderStatus());
        queryWrapper.like(ObjectUtil.isNotNull(pageQueryModel.getSubject()), PaymentIndent::getSubject, pageQueryModel.getSubject());
        queryWrapper.like(ObjectUtil.isNotNull(pageQueryModel.getBody()), PaymentIndent::getBody, pageQueryModel.getBody());
        queryWrapper.like(ObjectUtil.isNotNull(pageQueryModel.getCreateTime()), PaymentIndent::getCreateTime, pageQueryModel.getCreateTime());
        queryWrapper.orderByDesc(PaymentIndent::getCreateTime);
        return this.list(queryWrapper);
    }

    /**
     * 支付订单添加
     *
     * @param saveModel 支付订单
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void save(PaymentIndentSaveModel saveModel) {
        log.info("开始创建支付订单，请求数据：{}", saveModel);
        
        try {
            // 1. 参数验证
            validateSaveModel(saveModel);
            String orderNo = saveModel.getOrderNo();
            log.info("使用订单号：{}", orderNo);
            
            // 2. 检查订单号是否已存在
            if (existsByOrderNo(orderNo)) {
                log.warn("订单号已存在：{}", orderNo);
                throw new IllegalArgumentException("订单号已存在：" + orderNo);
            }
            
            // 3. 创建支付订单
            PaymentIndent paymentIndent = buildPaymentIndent(saveModel, orderNo);
            
            log.info("准备保存支付订单：{}", paymentIndent);
            this.save(paymentIndent);
            log.info("支付订单保存成功，ID：{}，订单号：{}", paymentIndent.getId(), orderNo);
            
            // 4. 如果有支付类型，同步到支付订单记录表
            if (saveModel.getPayType() != null) {
                syncToPaymentOrder(paymentIndent, saveModel.getPayType());
            }
            
        } catch (IllegalArgumentException e) {
            log.error("参数验证失败：{}", e.getMessage());
            throw e;
        } catch (Exception e) {
            log.error("创建支付订单失败，订单号：{}", saveModel.getOrderNo(), e);
            throw new RuntimeException("创建支付订单失败：" + e.getMessage(), e);
        }
    }

    /**
     * 支付订单添加并返回订单号
     *
     * @param saveModel 支付订单添加模型
     * @return 生成的订单号
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String saveAndReturnOrderNo(PaymentIndentSaveModel saveModel) {
        log.info("开始创建支付订单，请求数据：{}", saveModel);
        
        // 1. 生成订单号（如果未提供）
        String orderNo = saveModel.getOrderNo();
        if (orderNo == null || orderNo.trim().isEmpty()) {
            orderNo = generateOrderNo();
            log.info("自动生成订单号：{}", orderNo);
        }
        
        // 2. 创建支付订单
        // 设置默认过期时间为7天后
        Date defaultExpireTime = new Date(System.currentTimeMillis() + 7 * 24 * 60 * 60 * 1000L);
        Date expireTime = saveModel.getExpireTime() != null ? saveModel.getExpireTime() : defaultExpireTime;
        
        PaymentIndent paymentIndent = PaymentIndent.builder()
                .orderNo(orderNo)
                .amount(saveModel.getAmount())
                .userId(saveModel.getUserId())
                .orderStatus(saveModel.getOrderStatus() != null ? saveModel.getOrderStatus() : 1) // 默认待支付
                .subject(saveModel.getSubject())
                .body(saveModel.getBody())
                .expireTime(expireTime) // 使用默认7天后的过期时间
                .createTime(new Date())
                .build();
        
        log.info("准备保存支付订单：{}", paymentIndent);
        this.save(paymentIndent);
        log.info("支付订单保存成功，ID：{}，订单号：{}", paymentIndent.getId(), orderNo);
        
        // 3. 如果有支付类型，同步到支付订单记录表并标记为已支付
        if (saveModel.getPayType() != null) {
            try {
                // 先更新支付订单状态为已支付
                updateOrderStatus(orderNo, OrderEnum.PAID.getCode());
                
                // 同步到支付订单记录表（带支付类型）
                PaymentIndent updatedIndent = getByOrderNo(orderNo);
                if (updatedIndent != null) {
                    paymentDataSyncService.syncIndentToOrder(updatedIndent, saveModel.getPayType());
                    log.info("支付订单创建成功并同步到记录表，订单号：{}，支付类型：{}", orderNo, saveModel.getPayType());
                }
            } catch (Exception e) {
                log.error("同步到支付记录表失败，订单号：{}", orderNo, e);
                // 不抛出异常，避免影响主流程
            }
        }
        
        return orderNo;
    }

    /**
     * 支付订单修改
     *
     * @param editModel 支付订单
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void edit(PaymentIndentEditModel editModel) {
        PaymentIndent paymentIndent = PaymentIndent.builder()
                .id(editModel.getId())
                .orderNo(editModel.getOrderNo())
                .amount(editModel.getAmount())
                .userId(editModel.getUserId())
                .orderStatus(editModel.getOrderStatus())
                .subject(editModel.getSubject())
                .body(editModel.getBody())
                .expireTime(editModel.getExpireTime())
                .build();
        this.updateById(paymentIndent);
    }

    /**
     * 根据订单号查询支付订单
     * @param orderNo 订单号
     * @return 支付订单
     */
    @Override
    public PaymentIndent getByOrderNo(String orderNo) {
        return baseMapper.getByOrderNo(orderNo);
    }

    /**
     * 检查订单是否存在
     * @param orderNo 订单号
     * @return 是否存在
     */
    @Override
    public boolean existsByOrderNo(String orderNo) {
        return baseMapper.existsByOrderNo(orderNo);
    }

    /**
     * 更新订单状态
     * @param orderNo 订单号
     * @param status 新状态
     * @return 是否成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateOrderStatus(String orderNo, Integer status) {
        LambdaUpdateWrapper<PaymentIndent> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(PaymentIndent::getOrderNo, orderNo)
                .set(PaymentIndent::getOrderStatus, status);
        return this.update(updateWrapper);
    }

    /**
     * 处理支付成功回调
     * @param callbackReq 支付回调请求
     * @return 支付回调响应
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PaymentCallbackResp handlePaymentCallback(PaymentCallbackReq callbackReq) {
        log.info("处理支付回调，订单号：{}", callbackReq.getOrderNo());
        
        try {
            // 1. 参数验证
            validateCallbackRequest(callbackReq);
            
            // 2. 查询支付订单
            PaymentIndent paymentIndent = getByOrderNo(callbackReq.getOrderNo());
            if (paymentIndent == null) {
                log.warn("支付订单不存在，订单号：{}", callbackReq.getOrderNo());
                return buildFailResponse(callbackReq.getOrderNo(), "订单不存在");
            }

            // 3. 检查订单状态，只有待支付状态才能处理
            if (paymentIndent.getOrderStatus() != 1) {
                log.warn("订单状态不是待支付，订单号：{}，当前状态：{}", callbackReq.getOrderNo(), paymentIndent.getOrderStatus());
                return buildSuccessResponse(callbackReq, paymentIndent.getOrderStatus(), "订单已处理");
            }

            // 4. 更新支付订单状态为已支付
            boolean updateSuccess = updateOrderStatus(callbackReq.getOrderNo(), 2);
            if (!updateSuccess) {
                log.error("更新支付订单状态失败，订单号：{}", callbackReq.getOrderNo());
                return buildFailResponse(callbackReq.getOrderNo(), "更新订单状态失败");
            }

            // 5. 同步到支付订单记录表
            boolean syncSuccess = syncPaymentToOrder(paymentIndent, callbackReq);
            if (!syncSuccess) {
                log.error("同步到支付订单记录表失败，订单号：{}", callbackReq.getOrderNo());
                // 回滚支付订单状态
                updateOrderStatus(callbackReq.getOrderNo(), 1);
                return buildFailResponse(callbackReq.getOrderNo(), "同步支付记录失败");
            }

            log.info("支付回调处理成功，订单号：{}", callbackReq.getOrderNo());
            return buildSuccessResponse(callbackReq, 2, "支付成功");

        } catch (IllegalArgumentException e) {
            log.error("参数验证失败：{}", e.getMessage());
            return buildFailResponse(callbackReq.getOrderNo(), "参数验证失败：" + e.getMessage());
        } catch (Exception e) {
            log.error("处理支付回调异常，订单号：{}", callbackReq.getOrderNo(), e);
            return buildFailResponse(callbackReq.getOrderNo(), "处理异常：" + e.getMessage());
        }
    }

    /**
     * 获取状态名称
     */
    private String getStatusName(Integer status) {
        return switch (status) {
            case 1 -> "待支付";
            case 2 -> "已支付";
            case 3 -> "已完成";
            case 4 -> "已取消";
            default -> "未知状态";
        };
    }

    /**
     * 生成订单号
     * 使用雪花算法生成分布式ID，确保全局唯一性
     * 格式：NO + 雪花算法生成的ID
     * 例如：NO1234567890123456789
     */
    private String generateOrderNo() {
        // 使用专业的雪花算法ID生成器
        String snowflakeId = IdGenerator.generateId();
        return "NO" + snowflakeId;
    }

    /**
     * 验证保存模型参数
     * @param saveModel 保存模型
     */
    private void validateSaveModel(PaymentIndentSaveModel saveModel) {
        if (saveModel == null) {
            throw new IllegalArgumentException("保存模型不能为空");
        }
        if (saveModel.getOrderNo() == null || saveModel.getOrderNo().trim().isEmpty()) {
            throw new IllegalArgumentException("订单号不能为空");
        }
        if (saveModel.getAmount() == null || saveModel.getAmount().compareTo(java.math.BigDecimal.ZERO) <= 0) {
            throw new IllegalArgumentException("订单金额必须大于0");
        }
        if (saveModel.getUserId() == null) {
            throw new IllegalArgumentException("用户ID不能为空");
        }
        if (saveModel.getSubject() == null || saveModel.getSubject().trim().isEmpty()) {
            throw new IllegalArgumentException("订单名称不能为空");
        }
    }

    /**
     * 构建支付订单对象
     * @param saveModel 保存模型
     * @param orderNo 订单号
     * @return 支付订单对象
     */
    private PaymentIndent buildPaymentIndent(PaymentIndentSaveModel saveModel, String orderNo) {
        // 设置默认过期时间为7天后
        Date defaultExpireTime = new Date(System.currentTimeMillis() + 7 * 24 * 60 * 60 * 1000L);
        Date expireTime = saveModel.getExpireTime() != null ? saveModel.getExpireTime() : defaultExpireTime;
        
        return PaymentIndent.builder()
                .orderNo(orderNo)
                .amount(saveModel.getAmount())
                .userId(saveModel.getUserId())
                .orderStatus(saveModel.getOrderStatus() != null ? saveModel.getOrderStatus() : 1) // 默认待支付
                .subject(saveModel.getSubject())
                .body(saveModel.getBody())
                .expireTime(expireTime)
                .remark(saveModel.getRemark())
                .createTime(new Date())
                .build();
    }

    /**
     * 同步到支付订单记录表
     * @param paymentIndent 支付订单
     * @param payType 支付类型
     */
    private void syncToPaymentOrder(PaymentIndent paymentIndent, Long payType) {
        try {
            // 先更新支付订单状态为已支付
            updateOrderStatus(paymentIndent.getOrderNo(), OrderEnum.PAID.getCode());
            
            // 同步到支付订单记录表（带支付类型）
            PaymentIndent updatedIndent = getByOrderNo(paymentIndent.getOrderNo());
            if (updatedIndent != null) {
                paymentDataSyncService.syncIndentToOrder(updatedIndent, payType);
                log.info("支付订单创建成功并同步到记录表，订单号：{}，支付类型：{}", 
                        paymentIndent.getOrderNo(), payType);
            }
        } catch (Exception e) {
            log.error("同步到支付记录表失败，订单号：{}", paymentIndent.getOrderNo(), e);
            // 不抛出异常，避免影响主流程
        }
    }

    /**
     * 验证回调请求参数
     * @param callbackReq 回调请求
     */
    private void validateCallbackRequest(PaymentCallbackReq callbackReq) {
        if (callbackReq == null) {
            throw new IllegalArgumentException("回调请求不能为空");
        }
        if (callbackReq.getOrderNo() == null || callbackReq.getOrderNo().trim().isEmpty()) {
            throw new IllegalArgumentException("订单号不能为空");
        }
        if (callbackReq.getThirdTradeNo() == null || callbackReq.getThirdTradeNo().trim().isEmpty()) {
            throw new IllegalArgumentException("第三方交易号不能为空");
        }
        if (callbackReq.getPayChannel() == null || callbackReq.getPayChannel().trim().isEmpty()) {
            throw new IllegalArgumentException("支付渠道不能为空");
        }
    }

    /**
     * 构建成功响应
     * @param callbackReq 回调请求
     * @param orderStatus 订单状态
     * @param message 消息
     * @return 成功响应
     */
    private PaymentCallbackResp buildSuccessResponse(PaymentCallbackReq callbackReq, Integer orderStatus, String message) {
        return PaymentCallbackResp.builder()
                .orderNo(callbackReq.getOrderNo())
                .thirdTradeNo(callbackReq.getThirdTradeNo())
                .payChannel(callbackReq.getPayChannel())
                .payAmount(callbackReq.getPayAmount())
                .payTime(callbackReq.getPayTime())
                .orderStatus(orderStatus)
                .statusName(getStatusName(orderStatus))
                .result("SUCCESS")
                .message(message)
                .processTime(new Date())
                .build();
    }

    /**
     * 构建失败响应
     * @param orderNo 订单号
     * @param message 消息
     * @return 失败响应
     */
    private PaymentCallbackResp buildFailResponse(String orderNo, String message) {
        return PaymentCallbackResp.builder()
                .orderNo(orderNo)
                .result("FAIL")
                .message(message)
                .processTime(new Date())
                .build();
    }

    /**
     * 同步支付到订单记录表
     * @param paymentIndent 支付订单
     * @param callbackReq 回调请求
     * @return 是否成功
     */
    private boolean syncPaymentToOrder(PaymentIndent paymentIndent, PaymentCallbackReq callbackReq) {
        try {
            // 先检查支付记录表是否存在该订单
            PaymentOrder existingOrder = paymentOrderService.getByOrderNo(callbackReq.getOrderNo());
            
            if (existingOrder != null) {
                // 更新现有记录的状态为已支付
                Long payType = getPayTypeFromChannel(callbackReq.getPayChannel());
                return paymentOrderService.markPaidIfPending(
                        callbackReq.getOrderNo(),
                        callbackReq.getThirdTradeNo(),
                        callbackReq.getPayChannel(),
                        payType
                );
            } else {
                // 如果记录不存在，通过数据同步服务创建（带支付类型和支付时间）
                Long payType = getPayTypeFromChannel(callbackReq.getPayChannel());
                return paymentDataSyncService.syncIndentToOrder(
                        paymentIndent, 
                        payType, 
                        callbackReq.getPayTime(), 
                        callbackReq.getThirdTradeNo()
                );
            }
        } catch (Exception e) {
            log.error("同步支付到订单记录表失败，订单号：{}", callbackReq.getOrderNo(), e);
            return false;
        }
    }

    /**
     * 根据支付渠道获取支付类型
     * @param payChannel 支付渠道
     * @return 支付类型
     */
    private Long getPayTypeFromChannel(String payChannel) {
        if (payChannel == null) {
            return null;
        }
        return switch (payChannel.toLowerCase()) {
            case "wxpay" -> 1L; // 微信
            case "balance" -> 2L; // 余额
            case "alipay" -> 3L; // 支付宝
            default -> null;
        };
    }
}